/**
 * @file struct工具函数
 * @author  fanxl
 */

import type {SpecStruct, UnionSpecItem, ExtensionsAttr} from '../interface';
import type {ShallowObjectType} from '../hooks/types';
import {concat, groupBy, omit, map, set, each, isEmpty} from 'lodash-es';
import {updateSpecItem} from './spec';

interface RenderId2CompIndexMap {
    [key: string]: string[];
}

interface SafeArea {
    previewSize: string;
    safeAreaSize: string;
    safeAreaText: string;
    safeAreaTextTop: string;
    safeAreaTextBottom: string;
    safeAreaTextLeft: string;
    safeAreaTextRight: string;
    positionTop: number;
    positionLeft: number;
}

interface SafeAreaCondition {
    renderComponentId: number;
    path: string;
    pathArr?: string[];
    op: string;
    value: string | boolean | number;
}

export interface SafeAreaConfig {
    targetComponentId: number;
    path: string;
    pathArr?: string[];
    condition?: SafeAreaCondition;
    areas: SafeArea[];
}

function loopStructs(structs: SpecStruct[]): SpecStruct[] {
    let result: SpecStruct[] = [];
    structs.forEach((item) => {
        if (item.children?.length) {
            result = concat(result, loopStructs(item.children));
        }
        result.push(omit(item, 'children'));
    });
    return result;
}
// 构建渲染组件id 到 [componentIds]的映射
export function buildRenderId2CompIndexMap(data: SpecStruct[]): RenderId2CompIndexMap {
    if (!data || isEmpty(data)) {
        return {};
    }
    const structs: SpecStruct[] = concat([], data);
    const flatStructs: SpecStruct[] = loopStructs(structs);

    const renderComGroup = groupBy(flatStructs, 'renderComponentId') as ShallowObjectType<Array<SpecStruct>>;
    const resultMap: RenderId2CompIndexMap = {};
    Object.keys(renderComGroup).forEach((renderCompId: string) => {
        const sameStructs = renderComGroup[renderCompId];
        resultMap[renderCompId] = map(sameStructs, (item) => item.componentIndex);
    });
    return resultMap;
}
// 转换安全区配置中的componentId & path 为 pathArr
export function transAreaConfig(safeAreas: SafeAreaConfig[], compMap: RenderId2CompIndexMap) {
    if (!safeAreas || isEmpty(safeAreas)) {
        return [];
    }
    return map(safeAreas, (item: SafeAreaConfig) => {
        const compIndexes = compMap[`${item.targetComponentId}`];
        let path = item.path.replace(/\[\*\]/g, '.[*]');
        if (path.startsWith('.[*]')) {
            path = path.split('').slice(1).join('');
        }
        const pathArr: string[] = map(compIndexes, (comIndex) => {
            return `${comIndex}.${path}`;
        });
        const deps = item.condition;
        if (deps?.renderComponentId) {
            const depsCompIndexes = compMap[`${deps.renderComponentId}`];
            const depsPath = deps.path;
            const depsPathArr: string[] = map(depsCompIndexes, (comIndex) => {
                return `${comIndex}.${depsPath}`;
            });
            deps.pathArr = depsPathArr;
        }
        item.pathArr = pathArr;
        return item;
    });
}
// 将安全区配置转成插件配置
export function transSafeAreaExtensionToSpec(specs: UnionSpecItem[], safeAreas: SafeAreaConfig[]): UnionSpecItem[] {
    if (!specs) {
        return [];
    }
    if (!safeAreas || isEmpty(safeAreas)) {
        return specs;
    }
    const safeAreaCollection: SafeAreaConfig[] = [];
    safeAreas.forEach((item: SafeAreaConfig) => {
        const pathArr = item.pathArr || [];
        pathArr.forEach((path: string) => {
            safeAreaCollection.push({
                ...item,
                path
            });
        });
    });
    // 将安全区按照path进行分类
    const safeAreaGroup: ShallowObjectType<Array<SafeAreaConfig>> = groupBy(safeAreaCollection, 'path');

    each(safeAreaGroup, (collection: SafeAreaConfig[], path: string) => {
        const extensions: ExtensionsAttr = {
            name: 'safeArea',
            displayName: '查看安全区',
            params: [{safeAreaConfigs: collection}]
        };
        updateSpecItem(path, specs, (spec) => {
            if (spec.extraAttr?.extensions) {
                spec.extraAttr.extensions.push({...extensions});
            } else {
                set(spec, 'extraAttr.extensions', [{...extensions}]);
            }
        });
    });
    return specs;
}
